#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>



#include "constantes.h"
#include "estructuras.h"
#include "configuracion.h"
#include "estadisticas.h"

chs glChs;
int glRPM;
int sectores_totales_vda; 
char *data;
int posicionCabezal;
extern ListConfig * listaConfig; 


void initialize_disk () 
{
	int fd;
	struct stat sbuf;
		
	unsigned int size;
		
	if ((fd = open("/home/utn_so/fat32.disk", O_RDWR)) == -1) {
        perror("open");
        exit(1);
    }
    if (fstat(fd, &sbuf) < 0) {
        perror("fstat");
        exit(1);
    }
	size = lseek(fd, 0, SEEK_END);

    
	data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
	madvise(data,size,2);
	


}


int sectoresTotales(chs datosChs) {

	int resultado;

	resultado = datosChs.cabezal * datosChs.cilindros * datosChs.sectores;

	return resultado;
}


int capacidadTotal(chs datosChs, int sizeSector) {
	return sectoresTotales(datosChs)*sizeSector;   
}

/* chs: se le pasa una direccion logica y devuelve la pista correspondiente */
int calculaChs(int sector) {
	if (sector == -1) { return -1; }
	return sector/4;
}

/* Estadisticas VDA */


double rps(int rpm)
{
	return rpm/60;
}

double segundosPorVuelta(int rpm)
{
	return 1/rps(rpm);
}

double tiempoRotacional(chs auxChs, int rpm)/* Lo devuelve en ms */
{
	return (1000* /* para pasarlo a ms */segundosPorVuelta(rpm))/auxChs.sectores;
}




int getCilindro(int pos, chs auxChs)
{
	int resultado;

	resultado = pos/auxChs.sectores +1;


	
	return resultado;
}


int getCilindro2(int pos, chs auxChs)
{
	int resultado;

	if(pos%32!=0)
		resultado = pos/auxChs.sectores +1;
	else
		resultado = pos/auxChs.sectores;
	
	return resultado;
}

int ultimoSector( int cilindro, chs auxChs )
{
	int resultado;

	resultado = (cilindro -1)* auxChs.sectores;
	resultado = resultado + auxChs.sectores -1;

	return resultado;
}

int primerSector( int auxSector, chs auxChs )
{
	int resultado;

	resultado = auxSector + auxChs.sectores;

	return resultado;

}

char * readSector(int numsector){
	
	char *read_sec;
	int i;
	
	sleep(atoi(obtenerValor("t_Lectura")));
	read_sec=(char *)malloc(512);
	memcpy(read_sec, data + numsector * 512, 512);

	return read_sec;
}


int writeSector(int numsector,char* data_sector){
	
	int i;
	char aux;

	
	sleep(atoi(obtenerValor("t_Escritura")));
    memcpy(data+(numsector * 512),data_sector, 512);
	/*msync(data + (numsector * 512), 512, MS_SYNC);*/
	
	return 1; 
}	

char * imprimirSector(int numsector){

	char* aux_read;
	int i;
	
	aux_read = readSector(numsector);
		
	return aux_read;
}		

void Clean(int sector1,int sector2){

	int aux;
  
 
	char* data_sector=(char *)malloc(512);
	memset(data_sector,'0',512); 
	aux=sector1;
   
	while(aux!=sector2){
		writeSector(aux,(char *)data_sector);
		aux++;
	}
  

  
}	

int Trace(int vector[],int posCabezal,chs glChs){

	int i,f;
	int auxSectorBuscado;
	sectoresIntermedios listaSectoreYTiempos;

	
	
	i=0;
	while( i < 5  )
	{
		auxSectorBuscado = vector[i];
		if(vector[i] != -1)
		{	            
			auxSectorBuscado = vector[i];
			listaSectoreYTiempos = SectoresIntermedios_Actualiza(posCabezal,auxSectorBuscado,glChs,atof(obtenerValor("RPM")));
			printf("SECTORES RECORRIDOS: ");
			for( f = 0;f < listaSectoreYTiempos.tamanioVector;f++)
			{
				printf("%i:%d, ",getCilindro2(listaSectoreYTiempos.ptrSectoresLeidos[f],glChs),listaSectoreYTiempos.ptrSectoresLeidos[f]);
			}
			printf("\n");

			printf("TIEMPO CONSUMIDO: %f ms\n",listaSectoreYTiempos.tiempoDeAcceso);
			posCabezal=vector[i];

			/*sleep(5);*/
 
		}
		i++;
	}  
	
	return posCabezal;

}

sectoresIntermedios SectoresIntermedios(int posActual, int auxSectorBuscado, chs auxChs,float rpm)
{
	sectoresIntermedios resultadoSectoresLeidos;
	int a, tamanioMem;

	int *sectoresLeidos;

	tamanioMem = 0;
	a=0;
	
	if(posActual > auxSectorBuscado)
	{
		tamanioMem = 4*2;
		sectoresLeidos = (int*) malloc(tamanioMem); /* mem para este y el que viene */
		posActual = 0;
		sectoresLeidos[a] = posActual;
		a++;
	}
	else
	{
		tamanioMem = 4;
		sectoresLeidos = (int*) malloc (tamanioMem); /* mem para el que viene */
	}


	while(getCilindro(posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
		posActual = primerSector(posActual,auxChs);
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );

	}

	if(posActual > auxSectorBuscado)
	{
	/*
		posActual = auxSectorBuscado;
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
	*/
	
		while(posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
		}
		posActual = posActual - auxChs.sectores;

		while(posActual <= auxSectorBuscado) {
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}
	else
	{
		while(posActual != auxSectorBuscado )
		{
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;
			
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;
	resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	
	
	/* despues de usar la funcion hay que liberar memoria*/
	return resultadoSectoresLeidos;
	
}


sectoresIntermedios SectoresIntermedios_Actualiza(int posActual, int auxSectorBuscado, chs auxChs,float rpm)
{
	sectoresIntermedios resultadoSectoresLeidos;
	int a, tamanioMem;
	int posAux=posicionCabezal;
	
	int *sectoresLeidos;

	tamanioMem = 0;
	a=0;
	
	if(posActual > auxSectorBuscado)
	{
		tamanioMem = 4*2;
		sectoresLeidos = (int*) malloc(tamanioMem); /* mem para este y el que viene */
		posActual = 0;
		
		if(posAux!=posicionCabezal){
			SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
			posAux=posicionCabezal;
			posActual=posicionCabezal;
		}	
		
		sectoresLeidos[a] = posActual;
		a++;
	}
	else
	{
		tamanioMem = 4;
		sectoresLeidos = (int*) malloc (tamanioMem); /* mem para el que viene */
	}


	while(getCilindro(posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
	
		if(posAux!=posicionCabezal){
			SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
			posAux=posicionCabezal;
			posActual=posicionCabezal;
		}	
		
		posActual = primerSector(posActual,auxChs);
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );

	}

	if(posActual > auxSectorBuscado)
	{

	
		while(posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
				posActual=posicionCabezal;
			}	
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
		}
		
		if(posAux!=posicionCabezal){
			SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
			posAux=posicionCabezal;
			posActual=posicionCabezal;
		}	
		posActual = posActual - auxChs.sectores;

		while(posActual <= auxSectorBuscado) {
		
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
				posActual=posicionCabezal;
			}	
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;

			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}
	else
	{
		while(posActual != auxSectorBuscado )
		{
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
				posActual=posicionCabezal;
			}	
			posActual++;
			sectoresLeidos[a] = posActual;
			a++;
			
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;
	resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	
	
	/* despues de usar la funcion hay que liberar memoria*/
	return resultadoSectoresLeidos;
	
	/*
	if(posAux!=posicionCabezal){
		SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
		posAux=posicionCabezal;
	}	
	else{
		
		if(posAux!=posicionCabezal){
			SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
			posAux=posicionCabezal;
		}
		else{
			if(posActual > auxSectorBuscado)
			{
				tamanioMem = 4*2;
				sectoresLeidos = (int*) malloc(tamanioMem);*/ /* mem para este y el que viene */
				
				/*if(posAux!=posicionCabezal){
					SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
					posAux=posicionCabezal;
				}
				else{	
					posActual = 0;
					sectoresLeidos[a] = posActual;
					a++;
				}
			}
			else
			{
				tamanioMem = 4;
				sectoresLeidos = (int*) malloc (tamanioMem);*/ /* mem para el que viene */ /*
			}
		}
	}


	while(getCilindro(posActual, auxChs) != getCilindro(auxSectorBuscado, auxChs))
	{
		
		if(posAux!=posicionCabezal){
			SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
			posAux=posicionCabezal;
		}
		else{
			posActual = primerSector(posActual,auxChs);
			sectoresLeidos[a] = posActual;
			a++;
			tamanioMem = tamanioMem + sizeof(int);
			sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem );
		}
	}

	if(posActual > auxSectorBuscado)
	{
	*//*
		posActual = auxSectorBuscado;
		sectoresLeidos[a] = posActual;
		a++;
		
		tamanioMem = tamanioMem + sizeof(int);
		sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
	*/
	/*
		while(posActual <= ultimoSector( getCilindro(auxSectorBuscado,auxChs), auxChs )) {
			
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
			}
			else{
				posActual = posActual + 1;
				sectoresLeidos[a] = posActual;
				a++;
				tamanioMem = tamanioMem + sizeof(int);
				sectoresLeidos = (int*)realloc( sectoresLeidos, tamanioMem + sizeof(int));
			}
		}
		posActual = posActual - auxChs.sectores;

		while(posActual <= auxSectorBuscado) {
			
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
			}
			else{
				posActual = posActual + 1;
				sectoresLeidos[a] = posActual;
				a++;
				tamanioMem = tamanioMem + sizeof(int);
				sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
			}	
		}
	}
	else
	{
		while(posActual != auxSectorBuscado )
		{
			
			if(posAux!=posicionCabezal){
				SectoresIntermedios_Actualiza(posActual,posicionCabezal,auxChs,rpm);
				posAux=posicionCabezal;
			}
			else{
				posActual = posActual + 1;
				sectoresLeidos[a] = posActual;
				a++;
				tamanioMem = tamanioMem + sizeof(int);
				sectoresLeidos = (int*)realloc(sectoresLeidos, tamanioMem + sizeof(int) );
			}	
		}
	}

	resultadoSectoresLeidos.tamanioVector = a;
	resultadoSectoresLeidos.ptrSectoresLeidos = sectoresLeidos;
	resultadoSectoresLeidos.tiempoDeAcceso = a*tiempoRotacional(auxChs,rpm);
	*/
	
	/* despues de usar la funcion hay que liberar memoria*/
	/*return resultadoSectoresLeidos;
	*/
}